<?php

/**
 * Sunny软件公司欲开发一款实时在线股票软件，该软件需提供如下功能：
 * 当股票购买者所购买的某支股票价格变化幅度达到5%时，系统将自动发送通知（包括新价格）
 * 给购买该股票的所有股民。试使用观察者模式设计并实现该系统。
 */

/**
 * 目标类：股票中心
 */
abstract class StockCenter
{
	protected $name;
	protected $price;
	protected $observers;
	
	public function __construct($name, $price)
	{
		$this->name = $name;
		$this->price = $price;
		$this->observers = array();
		echo "{$name}创建成功，发行价：{$price}元/股。<br/>";
	}
	
	public function setPrice($price)
	{
		echo "股票价格现在为：{$price}元/股。<br/>";
		$oldPrice = $this->price;
		$this->price = $price;
		if ($price >= ($oldPrice * 1.05) || $price <= ($oldPrice * 0.95)) {
			$this->notify();
		}
	}
	
	public function getPrice()
	{
		return $this->price;
	}
	
	public function getName()
	{
		return $this->name;
	}
	
	/**
	 * 增加观察者
	 */
	public function attach(Observer $observer)
	{
		$this->observers[] = $observer;
		echo "{$observer->getName()}买入{$observer->getHoldings()}股。<br/>";
	}
	
	/**
	 * 删除观察者
	 */
	public function detach(Observer $observer)
	{
		$index = array_search($observer, $this->observers);
		if ($index !== false) {
			unset($this->observers[$index]);
		}
	}
	
	/**
	 * 通知所有观察者
	 */
	public abstract function notify();
}

/**
 * 具体目标类
 */
class ConcreteStockCenter extends StockCenter
{
	public function notify()
	{
		foreach ($this->observers as $observer) {
			$observer->update($this);
		}
	}
}

/**
 * 抽象观察者
 */
interface Observer
{
	public function update(StockCenter $stock);
}

/**
 * 具体观察者：股民
 */
class Investors implements Observer
{
	private $_name;
	private $_holdings;
	
	public function __construct($name, $holdings)
	{
		$this->_name = $name;
		$this->_holdings = $holdings;
	}
	
	public function getName()
	{
		return $this->_name;
	}
	
	public function getHoldings()
	{
		return $this->_holdings;
	}
	
	public function update(StockCenter $stock)
	{
		echo "通知：你好{$this->getName()}, 股票{$stock->getName()}现在价格为{$stock->getPrice()}元/股。<br/>";
	}
}

class Client
{
	public static function main()
	{
		//目标对象
		$stokCenter = new ConcreteStockCenter('股票xx', 30);
		
		$observer1 = new Investors('张三', '10000');
		$observer2 = new Investors('李四', '20000');
		$observer3 = new Investors('王五', '15000');
		
		$stokCenter->attach($observer1);
		$stokCenter->attach($observer2);
		$stokCenter->attach($observer3);
		
		$stokCenter->setPrice(31);
		$stokCenter->setPrice(32);
		$stokCenter->setPrice(34);
		$stokCenter->setPrice(25);
	}
}

client::main();